20 hashlib哈希加密
你想验证下载的文件是否被篡改、存储用户密码但不想明文保存、给数据生成唯一标识……这些都要用到哈希算法。hashlib模块就是Python的哈希工具箱。
一、什么是哈希
哈希(Hash)是把任意长度的数据转换为固定长度的"指纹"。相同的数据永远产生相同的哈希值,不同的数据(几乎)永远产生不同的哈希值。
输入: "Hello" → 哈希 → 8b1f4b9b4e4e4e4e4e4e4e4e4e4e4e4e
输入: "Hello" → 哈希 → 8b1f4b9b4e4e4e4e4e4e4e4e4e4e4e4e(相同)
输入: "hello" → 哈希 → 5d41402abc4b2a76b9719d911017c592(不同)二、常用哈希算法
2.1 MD5
python
import hashlib
# 计算MD5
data = "Hello, World!"
hash_obj = hashlib.md5(data.encode())
print(hash_obj.hexdigest())
# 65a8e27d8879283831b664bd8b7f0ad4注意:MD5已被破解,不推荐用于安全场景,但可以用于数据校验。
2.2 SHA-256
python
import hashlib
# 计算SHA-256
data = "Hello, World!"
hash_obj = hashlib.sha256(data.encode())
print(hash_obj.hexdigest())
# dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986fSHA-256是目前最常用的哈希算法,安全性高。
2.3 其他算法
python
import hashlib
data = "Hello, World!".encode()
# SHA-1(已被破解,不推荐)
hashlib.sha1(data).hexdigest()
# SHA-224
hashlib.sha224(data).hexdigest()
# SHA-384
hashlib.sha384(data).hexdigest()
# SHA-512
hashlib.sha512(data).hexdigest()
# SHA-3系列
hashlib.sha3_256(data).hexdigest()
hashlib.sha3_512(data).hexdigest()
# BLAKE2(推荐,比SHA-256快)
hashlib.blake2b(data).hexdigest()
hashlib.blake2s(data).hexdigest()2.4 查看支持的算法
python
import hashlib
# 保证可用的算法
print(hashlib.algorithms_guaranteed)
# {'sha3_256', 'sha3_512', 'sha3_384', 'sha3_224', 'sha1', ...}
# 平台可用的算法(可能更多)
print(hashlib.algorithms_available)三、分步计算
3.1 update()方法
python
import hashlib
hash_obj = hashlib.sha256()
# 分步更新
hash_obj.update(b"Hello, ")
hash_obj.update(b"World!")
print(hash_obj.hexdigest())
# 和一次性计算的结果相同3.2 处理大文件
python
import hashlib
def file_hash(filepath, algorithm="sha256"):
"""计算文件的哈希值"""
hash_obj = hashlib.new(algorithm)
with open(filepath, "rb") as f:
while chunk := f.read(8192): # 每次读8KB
hash_obj.update(chunk)
return hash_obj.hexdigest()
# 使用
print(file_hash("data.txt"))3.3 file_digest()(3.11+)
python
import hashlib
with open("data.txt", "rb") as f:
digest = hashlib.file_digest(f, "sha256")
print(digest.hexdigest())四、哈希对象方法
4.1 常用方法
python
import hashlib
hash_obj = hashlib.sha256(b"Hello")
# hexdigest():返回十六进制字符串
print(hash_obj.hexdigest())
# digest():返回字节
print(hash_obj.digest())
# copy():复制哈希对象
hash_copy = hash_obj.copy()
print(hash_copy.hexdigest()) # 相同4.2 属性
python
import hashlib
hash_obj = hashlib.sha256(b"Hello")
# digest_size:摘要大小(字节)
print(hash_obj.digest_size) # 32
# block_size:块大小(字节)
print(hash_obj.block_size) # 64
# name:算法名称
print(hash_obj.name) # sha256五、实战场景
5.1 文件完整性校验
python
import hashlib
def verify_file(filepath, expected_hash, algorithm="sha256"):
"""验证文件完整性"""
actual_hash = file_hash(filepath, algorithm)
return actual_hash == expected_hash
# 使用
expected = "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f"
if verify_file("download.zip", expected):
print("文件完整")
else:
print("文件被篡改")5.2 密码存储
python
import hashlib
import os
def hash_password(password):
"""哈希密码(加盐)"""
salt = os.urandom(32)
hash_obj = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 100000)
return salt + hash_obj
def verify_password(password, stored_hash):
"""验证密码"""
salt = stored_hash[:32]
stored_hash_obj = stored_hash[32:]
hash_obj = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 100000)
return hash_obj == stored_hash_obj
# 使用
hashed = hash_password("my_secret_password")
print(verify_password("my_secret_password", hashed)) # True
print(verify_password("wrong_password", hashed)) # False5.3 数据去重
python
import hashlib
def content_hash(data):
"""计算内容哈希"""
return hashlib.md5(data.encode()).hexdigest()
# 用哈希值去重
seen = set()
data_list = ["hello", "world", "hello", "python", "world"]
for item in data_list:
h = content_hash(item)
if h not in seen:
seen.add(h)
print(f"新数据: {item}")
else:
print(f"重复: {item}")5.4 生成唯一ID
python
import hashlib
from datetime import datetime
def generate_id(prefix=""):
"""生成唯一ID"""
data = f"{prefix}{datetime.now().isoformat()}{os.urandom(8).hex()}"
return hashlib.md5(data.encode()).hexdigest()[:12]
print(generate_id("user")) # a1b2c3d4e5f6
print(generate_id("order")) # 789012345678六、BLAKE2:更快的替代
python
import hashlib
data = b"Hello, World!"
# BLAKE2b:输出可变长(最多64字节)
hash_obj = hashlib.blake2b(data, digest_size=16)
print(hash_obj.hexdigest()) # 32个十六进制字符
# BLAKE2s:输出可变长(最多32字节)
hash_obj = hashlib.blake2s(data, digest_size=16)
print(hash_obj.hexdigest())
# BLAKE2比SHA-256快,安全性也足够七、密钥派生函数
7.1 PBKDF2
python
import hashlib
import os
password = b"my_password"
salt = os.urandom(16)
# PBKDF2:慢哈希,防止暴力破解
dk = hashlib.pbkdf2_hmac("sha256", password, salt, 100000)
print(dk.hex())7.2 scrypt
python
import hashlib
import os
password = b"my_password"
salt = os.urandom(16)
# scrypt:比PBKDF2更安全
dk = hashlib.scrypt(password, salt=salt, n=2**14, r=8, p=1)
print(dk.hex())八、常见问题
8.1 编码问题
python
import hashlib
# 字符串必须编码后才能哈希
data = "你好"
# hashlib.sha256(data) # TypeError
hashlib.sha256(data.encode("utf-8")).hexdigest() # 正确8.2 盐值(Salt)
python
import hashlib
import os
# 不加盐:相同密码产生相同哈希
hash1 = hashlib.sha256("password".encode()).hexdigest()
hash2 = hashlib.sha256("password".encode()).hexdigest()
print(hash1 == hash2) # True
# 加盐:相同密码产生不同哈希
salt1 = os.urandom(16)
salt2 = os.urandom(16)
hash1 = hashlib.sha256(salt1 + "password".encode()).hexdigest()
hash2 = hashlib.sha256(salt2 + "password".encode()).hexdigest()
print(hash1 == hash2) # False九、总结
hashlib模块的核心:
| 函数 | 用途 |
|---|---|
md5() | MD5哈希(不推荐用于安全) |
sha256() | SHA-256哈希(推荐) |
sha512() | SHA-512哈希 |
blake2b() / blake2s() | BLAKE2哈希(更快) |
pbkdf2_hmac() | 密码哈希(加盐) |
scrypt() | 密码哈希(更安全) |
哈希对象方法:
| 方法 | 用途 |
|---|---|
update(data) | 更新数据 |
hexdigest() | 返回十六进制字符串 |
digest() | 返回字节 |
copy() | 复制哈希对象 |
使用场景:
- 文件完整性校验
- 密码存储(加盐)
- 数据去重
- 生成唯一ID
安全场景用SHA-256或BLAKE2,密码存储用PBKDF2或scrypt。